Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correct esm problem on windows #559

Merged

Conversation

David-Desmaisons
Copy link

When using tape on windows in a esm module (using "type": "module" in the project package.json), this exception is raised:

(node:7484) UnhandledPromiseRejectionWarning: Error [ERR_UNSUPPORTED_ESM_URL_SCHEME]: Only file and data URLs are
supported by the default ESM loader
    at Loader.defaultResolve [as _resolve] (internal/modules/esm/resolve.js:698:11)
    at Loader.resolve (internal/modules/esm/loader.js:97:40)
    at Loader.getModuleJob (internal/modules/esm/loader.js:243:28)
    at Loader.import (internal/modules/esm/loader.js:178:28)
    at importModuleDynamically (internal/modules/cjs/loader.js:1080:27)
    at exports.importModuleDynamicallyCallback (internal/process/esm_loader.js:37:14)
    at importOrRequire (C:\...\tests\node_modules\tape\bin\import-or-require.js:11:9)       
    at C:\...\tests\node_modules\tape\bin\tape:84:14
    at Array.reduce (<anonymous>)
    at importFiles (C:\...\tests\node_modules\tape\bin\tape:81:30)

In turns out that making explicit the file protocol in the importOrRequire resolves this problem.

@@ -8,7 +8,7 @@ module.exports = function importOrRequire(file) {
const ext = extnamePath(file);

if (ext === '.mjs' || (ext === '.js' && getPackageType.sync(file) === 'module')) {
return import(file);
return import("file://" + file);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will break if someone uses --require=packageName. You need to provide the flle:// on relative ESM paths yourself, I think.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am still not sure about the --import=packageName (only find the require and ignore option). Could you please give an example that would break with this fix?

@David-Desmaisons
Copy link
Author

I just made a test with the --require option and it seems that it is not calling the importOrRequire function:
image

Is it correct or I am missing something?

@ljharb
Copy link
Collaborator

ljharb commented Aug 17, 2021

Sorry, you’re right; i meant --import=packageName

@ljharb
Copy link
Collaborator

ljharb commented Aug 17, 2021

Also, on what node version are you seeing this issue? And what exact tape command are you running?

@codecov-commenter

This comment has been minimized.

@David-Desmaisons
Copy link
Author

Here is a minimal repo for reproduction using tape **/*.spec.js command:
https://github.com/David-Desmaisons/tape-tests

I am testing with node 12.

@ljharb
Copy link
Collaborator

ljharb commented Aug 17, 2021

You can’t pass unquoted globs to tools tho - your shell will expand them. Try putting quotes around the glob.

If that doesn’t fix it, I’ll take a look at your repro repo shortly.

@David-Desmaisons
Copy link
Author

I changed to:

  "scripts": {
    "test": "tape \"**/*.spec.js\""
  },

With the same results: it works on ubuntu but breaks on windows.

@ljharb
Copy link
Collaborator

ljharb commented Aug 17, 2021

interesting, ok. it's also notable you're not using --import or --require, which means this line of code shouldn't be executed. I don't have Windows to be able to test, unfortunately.

@ljharb
Copy link
Collaborator

ljharb commented Aug 18, 2021

Indeed, your repo passes fine on my Mac.

@David-Desmaisons
Copy link
Author

David-Desmaisons commented Aug 20, 2021

The path are constructed line 59 of tape.js file

image

It is then used using the import sintax but as on windows it is a windows path it is not compatible with an url:

image

Adding "file:\\" before the path resolve the windows case without breaking linux build.

@@ -8,7 +8,7 @@ module.exports = function importOrRequire(file) {
const ext = extnamePath(file);

if (ext === '.mjs' || (ext === '.js' && getPackageType.sync(file) === 'module')) {
return import(file);
return import('file://' + file);
Copy link
Contributor

@vweevers vweevers Nov 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm seeing the same issue on Windows (with node 16.9.1).

I suggest import(pathToFileURL(file).href), using const { pathToFileURL } = require('url') which was added in node 10.12.0. Prior art: unified-engine.

Copy link
Contributor

@vweevers vweevers Nov 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PS. The error message that I'm getting has a more complete explanation than the message shared in the OP. Running tape test.js yields:

Error [ERR_UNSUPPORTED_ESM_URL_SCHEME]: Only file and data URLs are supported by the default
ESM loader. On Windows, absolute paths must be valid file:// URLs. Received protocol 'c:'

That test.js file is an ESM file on C:\, within a package with { "type": "module" }, therefore hitting the import() if-branch as expected.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ljharb See nodejs/node@a084632. The error message was further tweaked in a later commit, but this should suffice to explain it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vweevers that makes sense, but I still need to find a way to repro it on windows (but i don't have a windows box) or a test that would have failed on windows (even though we're not running tests on windows yet)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you take a PR for a basic windows workflow on GitHub Actions (just on latest node to start), with a test? Can split those into 2 PRs if you prefer that

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but I prefer not to use the setup-node action, and I haven't yet adapted https://github.com/ljharb/actions/tree/main/node/install to work on windows yet.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, in that case I'll only send a PR for a test (if I can get existing tests to pass on Windows).

This is required on Windows if the argument passed to `import()` is
an absolute path. Without it `tape test.js` fails if test.js is ESM.

Covered by existing tests: `node test/import.js` fails without this.

See nodejs/node@a084632
@ljharb
Copy link
Collaborator

ljharb commented Nov 14, 2021

@David-Desmaisons thank you so much for bringing the problem to my attention; I'm going to go with the solution in #571, and longer term, we'll look into running CI tests on windows to prevent this kind of problem in the future.

@ljharb ljharb merged commit d487add into tape-testing:master Nov 14, 2021
ljharb added a commit that referenced this pull request Nov 16, 2021
 - [Fix] use `file://` URLs for dynamic `import()` (#571, #559)
 - [readme] hard wraps bad, soft wraps good
 - [readme] fix markdown; github still has a rendering bug
 - [readme] add badges
 - [meta] Exclude `fs` from browser bundles (#565)
 - [Deps] update `glob`, `string.prototype.trim`
 - [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `safe-publish-latest`, `array.prototype.flatmap`
 - [actions] update codecov uploader
 - [Tests] handle carriage returns in stack traces on Windows
 - [Tests] node 17+ smooshes a version number on the end of the stack trace
 - [Tests] handle v8 6.9 changing an error message
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants